package com.csq.androidproject.views.draggridview;

import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;

/**
 * 可拖拽排序的GridView
 * 
 * @author chenshiqiang csqwyyx@163.com
 */
public class MyDragGridView extends ViewGroup implements OnTouchListener, OnLongClickListener{
    
    /**
     * 动画时间
     */
    private static int ANIMATION_DURATION = 250;
    
    /**
     * 是否移动到边缘的判定值
     */
    private static int EGDE_DETECTION_MARGIN = 35;
    
    /**
     * 列数
     */
    private int columnNum = 3;
    
    /**
     * item间距
     */
    private int itemSpace = 5;
    
    /**
     * 每个item的大小
     */
    private int perSize = 0;
    
    /**
     * 是否正在拖拽
     */
    private boolean isDraging = false;
    
    /**
     * 拖拽目的地序号
     */
    private int dragTargetLayoutIndex = -1;
    
    /**
     * 记录当前触摸位置
     */
    private float curTouchX;
    private float curTouchY;
    
    private ListAdapter adapter;
    
    public MyDragGridView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        init();
    }
    
    public MyDragGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        init();
    }
    
    public MyDragGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        init();
    }
    
    private void init() {
        if (isInEditMode() && adapter == null) {
            useEditModeAdapter();
        }
        
        setOnLongClickListener(this);
        setOnTouchListener(this);
    }
    
    //************************************ Override ****************************************
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int spaceMeasureSpec = MeasureSpec.makeMeasureSpec(itemSpace, MeasureSpec.EXACTLY);
        //Ask all of the children of this view to measure themselves,不调子View显示不了
        int itemSize = (widthMeasureSpec - (columnNum-1)*spaceMeasureSpec)/columnNum;
        measureChildren(itemSize, itemSize);
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        // TODO Auto-generated method stub
        super.onSizeChanged(w, h, oldw, oldh);
        perSize = (w - (columnNum-1)*itemSpace)/columnNum;
    }
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // TODO Auto-generated method stub
        for (int childIndex = 0; childIndex < adapter.getCount(); childIndex++) {
            layoutAChild(childIndex);
        }
    }
    
    private void layoutAChild(int childIndex) {
        Rect r = getRectForIndex(childIndex);
        View cView = getChildAt(childIndex);
        cView.layout(r.left, r.top, r.right, r.bottom);
    }
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        int action = event.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            touchDown(event);
            break;
        case MotionEvent.ACTION_MOVE:
            touchMove(event);
            break;
        case MotionEvent.ACTION_UP:
            touchUp(event);
            break;
        }
        if (isDragingAview())
            return true;
        return false;
    }

    @Override
    public boolean onLongClick(View v) {
        // TODO Auto-generated method stub
        int draggedItemIndex = getViewIndexAtCoordinate((int)curTouchX,(int)curTouchY);
        if(draggedItemIndex > -1){
            getChildAt(draggedItemIndex).bringToFront();
            animateMoveAllItems();
            animateDragged();
            dragTargetLayoutIndex = draggedItemIndex;
            isDraging = true;
            return true;
        }
        return false;
    }

    
    //************************************ 数据 ****************************************
    private void useEditModeAdapter() {
        adapter = new BaseAdapter() {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                return null;
            }
            
            @Override
            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return 0;
            }
            
            @Override
            public Object getItem(int position) {
                // TODO Auto-generated method stub
                return null;
            }
            
            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return 0;
            }
        };
    }
    
    /**
     * 设置数据
     */
    public void setAdapter(ListAdapter adapter) {
        this.adapter = adapter;
        removeAllViews();
        if(adapter != null){
            View cView = null;
            for(int i = 0,num=adapter.getCount() ; i < num ; i++){
                cView = adapter.getView(i, null, null);
                //暂且每个子View分配一个正方形空间
                addView(cView);
            }
        }
    }
    
    //************************************ 位置 ****************************************
    
    /**
     * 获取指定索引的布局范围
     */
    private Rect getRectForIndex(int index) {
        //行
        int row = index / columnNum;
        //列
        int col = index - (row * columnNum);

        //暂且每个子View分配一个正方形空间
        int left = col*(perSize+itemSpace);
        int right = left + perSize;
        int top = row*(perSize+itemSpace);
        int buttom = top + perSize;
        return new Rect(left, top, right, buttom);
    }
    
    /**
     * 根据view坐标获取点击的子view序号(在ViewGroup中的序号)
     */
    private int getViewIndexAtCoordinate(int x,int y) {
        //getChildCount()-1不包含拖拽的View
        for (int index = 0,size = getChildCount()-1; index < size; index++) {
            View child = getChildAt(index);
            int l = child.getLeft();
            int r = child.getRight();
            int t = child.getTop();
            int b =child.getBottom();
            Rect rect = new Rect(l,t,r,b);
            if (rect.contains((int)curTouchX, (int)curTouchY)) {
                return index;
            }
        }
        return -1;
    }
    
    /**
     * 获得点击坐标的布局位置
     */
    private int getLayoutIndexAtCoordinate(int x,int y) {
        //行
        int row = y/(perSize+itemSpace);
        //列
        int col = x/(perSize+itemSpace);
        
        return row * columnNum + col;
    }
    
    private void touchDown(MotionEvent event) {
        curTouchX = event.getX();
        curTouchY = event.getY();
    }
    
    private void touchMove(MotionEvent event) {
        if(isDragingAview()){
            curTouchX = event.getX();
            curTouchY = event.getY();
            moveDraggedView((int)curTouchX, (int)curTouchY);
            manageSwapPosition((int)curTouchX, (int)curTouchY);
        }
    }
    
    private void touchUp(MotionEvent event) {
        if(isDragingAview()){
            isDraging = false;
            cancelAnimations();
            moveDragToTarget();
        }
    }
    
    /**
     * 移动拖拽的item到目的地
     */
    private void moveDragToTarget(){
        if(dragTargetLayoutIndex >= 0){
            Rect dest = getRectForIndex(dragTargetLayoutIndex);
            getDraggedView().layout(dest.left, dest.top, dest.right, dest.bottom);
        }
        dragTargetLayoutIndex = -1;
    }
    
    /**
     * 是否正在拖拽一个view
     */
    private boolean isDragingAview(){
        return isDraging;
    }
    
    
    /**
     * 获得正在拖拽的View
     */
    private View getDraggedView() {
        if(getChildCount() > 0){
            //每次都会将点击的View移动到最上层
            return getChildAt(getChildCount()-1);
        }
        return null;
    }
    
    /**
     * 移动拖拽的view
     */
    private void moveDraggedView(int x, int y) {
        View childAt = getDraggedView();        
        
        int width = childAt.getMeasuredWidth();
        int height = childAt.getMeasuredHeight();

        int l = x - (1 * width / 2);
        int t = y - (1 * height / 2);

        childAt.layout(l, t, l + width, t + height);
    }
    
    /**
     * 管理拖拽时为止交换
     */
    private void manageSwapPosition(int x, int y) {
        int target = getLayoutIndexAtCoordinate(x, y);
        if (target != dragTargetLayoutIndex) {
            int viewIndex = getViewIndexAtCoordinate(x, y);
            if(viewIndex >= 0){
                //目标地点有View，替换
                View changeView = getChildAt(viewIndex);
                
                Rect d = getRectForIndex(dragTargetLayoutIndex);
                changeView.layout(d.left, d.top, d.right, d.bottom);
                
                debug("swaping   move  from-->to = "+target+"-->"+dragTargetLayoutIndex);
            }
        }
        dragTargetLayoutIndex = target;
    }
    
    /**
     * 获取指定布局位置的左上角坐标
     */
    private Point getOffsetAtLayoutPosition(int layoutPosition){
        //行
        int row = layoutPosition / columnNum;
        //列
        int col = layoutPosition % columnNum;
        return new Point(col * (perSize + itemSpace), row * (perSize + itemSpace));
    }
    
    
    //************************************ 动画 ****************************************
    /**
     * 创建快速摇晃动画
     */
    private Animation createFastRotateAnimation() {
        Animation rotate = new RotateAnimation(-2.0f,
                                          2.0f,
                                          Animation.RELATIVE_TO_SELF,
                                          0.5f,
                                          Animation.RELATIVE_TO_SELF,
                                          0.5f);

        rotate.setRepeatMode(Animation.REVERSE);
        rotate.setRepeatCount(Animation.INFINITE);
        rotate.setDuration(60);
        rotate.setInterpolator(new AccelerateDecelerateInterpolator());
        return rotate;
    }
    
    /**
     * 拖拽时所有view开始摇晃动画
     */
    private void animateMoveAllItems() {
        Animation rotateAnimation = createFastRotateAnimation();

        for (int i=0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.startAnimation(rotateAnimation);
         }
    }

    /**
     * 拖拽后所有view停止摇晃动画
     */
    private void cancelAnimations() {
         for (int i=0; i < getChildCount(); i++) {
             View child = getChildAt(i);
             child.clearAnimation();
         }
    }
    
    /**
     * 拖拽开始放大效果
     */
    private void animateDragged() {
        int perSize = getWidth()/columnNum;
        ScaleAnimation scale = new ScaleAnimation(1f, 1.4f, 1f, 1.4f, perSize / 2 , perSize / 2);
        scale.setDuration(200);
        scale.setFillAfter(true);
        scale.setFillEnabled(true);

        if (isDragingAview()) {
            View draggedView = getDraggedView();
            if(draggedView != null){
                draggedView.clearAnimation();
                draggedView.startAnimation(scale);
            }
        }
    }
    
    /**
     * 移动targetView到新的位置
     */
    /*private void animateMoveToNewPosition(View targetView, int oldLayoutPosition, int newLayoutPosition) {
        animateMoveToNewPosition(targetView, 
            getOffsetAtLayoutPosition(oldLayoutPosition), 
            getOffsetAtLayoutPosition(newLayoutPosition));
    }*/
    
    /**
     * 移动targetView到新的位置
     */
    /*private void animateMoveToNewPosition(View targetView, Point oldOffset, Point newOffset) {
        debug("animateMoveToNewPosition  from-->to = "+oldOffset.x+":"+oldOffset.y
            +"-->"+newOffset.x+":"+newOffset.y);
        
        AnimationSet set = new AnimationSet(true);

        Animation rotate = createFastRotateAnimation();
        Animation translate = createTranslateAnimation(oldOffset, newOffset);

        set.addAnimation(rotate);
        set.addAnimation(translate);

        targetView.clearAnimation();
        targetView.startAnimation(set);
    }

    private TranslateAnimation createTranslateAnimation(Point oldOffset, Point newOffset) {
        TranslateAnimation translate = new TranslateAnimation(Animation.ABSOLUTE, oldOffset.x,
                                                              Animation.ABSOLUTE, newOffset.x,
                                                              Animation.ABSOLUTE, oldOffset.y,
                                                              Animation.ABSOLUTE, newOffset.y);
        translate.setDuration(ANIMATION_DURATION);
        translate.setFillEnabled(true);
        translate.setFillAfter(true);
        translate.setInterpolator(new AccelerateDecelerateInterpolator());
        return translate;
    }*/
    
    //************************************ 调试 ****************************************
    private final boolean DEBUG = true;
    private void debug(String msg){
        if(DEBUG){
            Log.e("MyDragGridView", "===== "+msg);
        }
    }
}
